/**
 * @constructor
 * @returns {DistanceCalculator} A distance calculator that uses Euclidian distance (Pythagoras' Theorem)
 */
function DistanceCalculator() {}

DistanceCalculator.prototype = {
		/**
		 * @public
		 * @memberOf DistanceCalculator.prototype
		 * @param {Node} n1 
		 * @param {Node} n2
		 * @return{Number} the distance between the nodes n1 and n2
		 */
		getDistance: function(n1, n2) {
			var val = Math.sqrt(
					 Math.pow(UNIT_SIZE*(n1.x - n2.x), 2) + 
					 Math.pow(UNIT_SIZE*(n1.y - n2.y), 2)
					 );
			return val;
		},
		
		/**
		 * @public
		 * @memberOf DistanceCalculator.prototype
		 * @param {Node} node
		 * @param {Area} area
		 * @return {Array} - Array of Node objects representing the neighbors
		 */
		getNeighbors: function(node, area) {
			var leftN = null; var topN = null; var rightN = null; var bottomN = null;
			var leftUpperN = null; var rightUpperN = null; var rightLowerN = null; var leftLowerN = null;
			
			var nCount = 0;
			if(node.x>0 && area.getTerrainType(node.x-1, node.y)!=TerrainType.IMPASSABLE) {
				nCount++;
				leftN = new Node(node.x-1,node.y);				
			}
			if(node.x<area.getWidth()-1 && area.getTerrainType(node.x+1, node.y)!=TerrainType.IMPASSABLE) {
				nCount++;
				rightN = new Node(node.x+1,node.y);				
			}
			if(node.y>0 && area.getTerrainType(node.x, node.y-1)!=TerrainType.IMPASSABLE) {
				nCount++;
				topN = new Node(node.x, node.y-1);				
			}
			if(node.y<area.getHeight()-1 && area.getTerrainType(node.x, node.y+1)!=TerrainType.IMPASSABLE) {
				nCount++;
				bottomN = new Node(node.x, node.y+1);				
			}
			
			if(node.x>0 && node.y>0 && area.getTerrainType(node.x-1, node.y-1)!=TerrainType.IMPASSABLE) {
				nCount++;
				leftUpperN = new Node(node.x-1,node.y-1);
			}			
			if(node.x>0 && node.y<area.getHeight()-1 && area.getTerrainType(node.x-1, node.y+1)!=TerrainType.IMPASSABLE) {
				nCount++;
				leftLowerN  = new Node(node.x-1,node.y+1);
			}
			if(node.x<area.getWidth()-1 && node.y>0 && area.getTerrainType(node.x+1, node.y-1)!=TerrainType.IMPASSABLE) {
				nCount++;
				rightUpperN = new Node(node.x+1,node.y-1);
			}
			if(node.x<area.getWidth()-1 && node.y<area.getHeight()-1 && area.getTerrainType(node.x+1, node.y+1)!=TerrainType.IMPASSABLE) {
				nCount++;
				rightLowerN  = new Node(node.x+1,node.y+1);
			}
						
			var neighbors = new Array();
			nCount=0;
			
			if(leftN!=null) {
				neighbors[nCount++] = leftN;
			}
			if(topN!=null) {
				neighbors[nCount++] = topN;
			}
			if(rightN!=null) {
				neighbors[nCount++] = rightN;
			}
			if(bottomN!=null) {
				neighbors[nCount++] = bottomN;
			}
			
			if(leftUpperN!=null) {
				neighbors[nCount++] = leftUpperN;
			}
			if(leftLowerN!=null) {
				neighbors[nCount++] = leftLowerN;
			}
			if(rightUpperN!=null) {
				neighbors[nCount++] = rightUpperN;
			}
			if(rightLowerN!=null) {
				neighbors[nCount++] = rightLowerN;
			}
			
			return neighbors;
		}
};

/**
 * @constructor
 * @returns {ModifiedChebyshevDistanceCalculator} A distance calculator that uses Euclidian distance (using an update on Chebyshev Distance that takes into account diagonal movement)
 */
function ModifiedChebyshevDistanceCalculator() {
	
	this.diagUnitSize = Math.sqrt(2) * UNIT_SIZE;	

}

ModifiedChebyshevDistanceCalculator.prototype = Object.create(DistanceCalculator.prototype);
ModifiedChebyshevDistanceCalculator.prototype.constructor = ModifiedChebyshevDistanceCalculator;

/**
 * @public
 * @memberOf ModifiedChebyshevDistanceCalculator.prototype
 * @param {Node} n1 
 * @param {Node} n2
 * @return{Number} the distance between the nodes n1 and n2
 */
ModifiedChebyshevDistanceCalculator.prototype.getDistance = function(n1, n2) {	
	var xDist = Math.abs(n1.x - n2.x);
    var yDist = Math.abs(n1.y - n2.y);
    var val = UNIT_SIZE * (xDist + yDist) + (this.diagUnitSize - 2 * UNIT_SIZE) * Math.min(xDist, yDist);
    return val;
};